﻿/*
 * EmeCoder v1.2.1.168
 * 作者：Administrator/PC4APPLE
 * 时间：2013-09-27 04:23:50
 * 版权：版权所有 (C) Eme Development Team 2013
*/

﻿using System;
using System.ComponentModel;
using HmFramework.Data;

namespace CuteSprite.Eme.Data.CRM
{
	/// <summary>运单号回收</summary>
	[Serializable]
	[ModelCheckMode(ModelCheckModes.CheckTableWhenFirstUse)]
	public class DiscardedExpressNo : DiscardedExpressNo<DiscardedExpressNo> { }

	/// <summary>运单号回收</summary>
	public partial class DiscardedExpressNo<TEntity> : Entity<TEntity> where TEntity : DiscardedExpressNo<TEntity>, new()
	{
		#region 对象操作﻿

		static DiscardedExpressNo()
		{
			// 用于引发基类的静态构造函数，所有层次的泛型实体类都应该有一个
			TEntity entity = new TEntity();
		}

		///// <summary>验证数据，通过抛出异常的方式提示验证失败。</summary>
		///// <param name="isNew"></param>
		//public override void Valid(Boolean isNew)
		//{
		//	// 这里验证参数范围，建议抛出参数异常，指定参数名，前端用户界面可以捕获参数异常并聚焦到对应的参数输入框
		//	//if (String.IsNullOrEmpty(Name)) throw new ArgumentNullException(_.Name, _.Name.DisplayName + "无效！");
		//	//if (!isNew && ID < 1) throw new ArgumentOutOfRangeException(_.ID, _.ID.DisplayName + "必须大于0！");

		//	// 建议先调用基类方法，基类方法会对唯一索引的数据进行验证
		//	base.Valid(isNew);

		//	// 在新插入数据或者修改了指定字段时进行唯一性验证，CheckExist内部抛出参数异常
		//	//if (isNew || Dirtys[__.Name]) CheckExist(__.Name);
		//}

		///// <summary>首次连接数据库时初始化数据，仅用于实体类重载，用户不应该调用该方法</summary>
		//[EditorBrowsable(EditorBrowsableState.Never)]
		//protected override void InitData()
		//{
		//    base.InitData();

		//    // InitData一般用于当数据表没有数据时添加一些默认数据，该实体类的任何第一次数据库操作都会触发该方法，默认异步调用
		//    // Meta.Count是快速取得表记录数
		//    if (Meta.Count > 0) return;

		//    // 需要注意的是，如果该方法调用了其它实体类的首次数据库操作，目标实体类的数据初始化将会在同一个线程完成
		//    HmTrace.WriteDebug("开始初始化{0}[{1}]数据……", typeof(TEntity).Name, Meta.Table.DataTable.DisplayName);

		//    var entity = new DiscardedExpressNo();
		//    entity.ExpressCategory = 0;
		//    entity.ExpressNo = "abc";
		//    entity.Insert();

		//    HmTrace.WriteDebug("完成初始化{0}[{1}]数据！", typeof(TEntity).Name, Meta.Table.DataTable.DisplayName);
		//}

		///// <summary>已重载。基类先调用Valid(true)验证数据，然后在事务保护内调用OnInsert</summary>
		///// <returns></returns>
		//public override Int32 Insert()
		//{
		//    return base.Insert();
		//}

		///// <summary>已重载。在事务保护范围内处理业务，位于Valid之后</summary>
		///// <returns></returns>
		//protected override Int32 OnInsert()
		//{
		//    return base.OnInsert();
		//}

		#endregion

		#region 扩展属性﻿

		#endregion

		#region 扩展查询﻿

		/// <summary>根据运单类别、运单号查找</summary>
		/// <param name="expresscategory">运单类别</param>
		/// <param name="expressno">运单号</param>
		/// <returns></returns>
		[DataObjectMethod(DataObjectMethodType.Select, false)]
		public static TEntity FindByExpressCategoryAndExpressNo(ExpressBusinessCategory expresscategory, String expressno)
		{
			if (Meta.Count > 1000)
				return Find(new String[] { _.ExpressCategory, _.ExpressNo }, new Object[] { (Int32)expresscategory, expressno });
			else // 实体缓存
				return Meta.Cache.Entities.Find(e => e.ExpressCategory == (Int32)expresscategory && e.ExpressNo == expressno);
		}

		/// <summary>根据主键查找</summary>
		/// <param name="id">主键</param>
		/// <returns></returns>
		[DataObjectMethod(DataObjectMethodType.Select, false)]
		public static TEntity FindByID(Int32 id)
		{
			if (Meta.Count > 1000)
				return Find(_.ID, id);
			else // 实体缓存
				return Meta.Cache.Entities.Find(__.ID, id);
			// 单对象缓存
			//return Meta.SingleCache[id];
		}

		#endregion

		#region 高级查询

		// 以下为自定义高级查询的例子

		///// <summary>
		///// 查询满足条件的记录集，分页、排序
		///// </summary>
		///// <param name="key">关键字</param>
		///// <param name="orderClause">排序，不带Order By</param>
		///// <param name="startRowIndex">开始行，0表示第一行</param>
		///// <param name="maximumRows">最大返回行数，0表示所有行</param>
		///// <returns>实体集</returns>
		//[DataObjectMethod(DataObjectMethodType.Select, true)]
		//public static EntityList<TEntity> Search(String key, String orderClause, Int32 startRowIndex, Int32 maximumRows)
		//{
		//    return FindAll(SearchWhere(key), orderClause, null, startRowIndex, maximumRows);
		//}

		///// <summary>
		///// 查询满足条件的记录总数，分页和排序无效，带参数是因为ObjectDataSource要求它跟Search统一
		///// </summary>
		///// <param name="key">关键字</param>
		///// <param name="orderClause">排序，不带Order By</param>
		///// <param name="startRowIndex">开始行，0表示第一行</param>
		///// <param name="maximumRows">最大返回行数，0表示所有行</param>
		///// <returns>记录数</returns>
		//public static Int32 SearchCount(String key, String orderClause, Int32 startRowIndex, Int32 maximumRows)
		//{
		//    return FindCount(SearchWhere(key), null, null, 0, 0);
		//}

		///// <summary>构造搜索条件</summary>
		///// <param name="key">关键字</param>
		///// <returns></returns>
		//private static String SearchWhere(String key)
		//{
		//	// WhereExpression重载&和|运算符，作为And和Or的替代
		//	// SearchWhereByKeys系列方法用于构建针对字符串字段的模糊搜索
		//	var exp = SearchWhereByKeys(key, null);

		//	// 以下仅为演示，Field（继承自FieldItem）重载了==、!=、>、<、>=、<=等运算符（第4行）
		//	//if (userid > 0) exp &= _.OperatorID == userid;
		//	//if (isSign != null) exp &= _.IsSign == isSign.Value;
		//	//if (start > DateTime.MinValue) exp &= _.OccurTime >= start;
		//	//if (end > DateTime.MinValue) exp &= _.OccurTime < end.AddDays(1).Date;

		//	return exp;
		//}

		#endregion

		#region 扩展操作

		#endregion

		#region 业务

		private static Object _lockNo = new Object();

		/// <summary>自动产生运单号码</summary>
		/// <param name="category"></param>
		/// <returns></returns>
		public static String MakeExpressNextNo(ExpressBusinessCategory category)
		{
			lock (_lockNo)
			{
				String expressNo = null;

				// 首先查找运单号码回收表
				if (Meta.Count > 1000)
				{
					//var list = FindAll(_.ExpressCategory.Equal((Int32)category), null, null, 0, 1);
					// 因为当前只有富力通做运单号回收，忽略运单类别
					var list = FindAll(null, null, null, 0, 1);
					if (list != null && list.Count > 0)
					{
						expressNo = list[0].ExpressNo;
						list[0].Delete();
					}
				}
				else
				{
					//var list = Meta.Cache.Entities.FindAll(e => e.ExpressCategory == (Int32)category);
					// 因为当前只有富力通做运单号回收，忽略运单类别
					var list = Meta.Cache.Entities;
					if (list != null && list.Count > 0)
					{
						expressNo = list[0].ExpressNo;
						list[0].Delete();
					}
				}

				// 根据最后运单号码自动生成
				if (expressNo.IsNullOrWhiteSpace())
				{
					if (_LastExpressMixNo.IsNullOrWhiteSpace()) { _LastExpressMixNo = BsdSystemConfig.Current.LastExpressMixNo; }
					expressNo = MakeExpressMixNextNo(_LastExpressMixNo);
					_LastExpressMixNo = expressNo;
					BsdSystemConfig.Current.LastExpressMixNo = expressNo;
					BsdSystemConfig.Current.Save();
				}
				return expressNo;
			}
		}

		private static String _LastExpressMixNo = null;

		/// <summary>自动生成富力通运单号码</summary>
		/// <param name="currentNo"></param>
		/// <returns></returns>
		private static String MakeExpressMixNextNo(String currentNo)
		{
			//if (!currentNo.IsNullOrWhiteSpace() && currentNo.Length == 12)
			//{
			//	string newBehindFirstBit = string.Empty;
			//	string frontElevenBits = currentNo.Substring(0, 11);
			//	string behindFirstBit = currentNo.Substring(11, 1);
			//	string behindSecondBit = currentNo.Substring(10, 1);
			//	string behindThirdBit = currentNo.Substring(9, 1);
			if (!currentNo.IsNullOrWhiteSpace() && currentNo.Length == 11)
			{
				var newBehindFirstBit = String.Empty;
				var frontElevenBits = currentNo.Substring(0, 10);
				var behindFirstBit = currentNo.Substring(10, 1);
				var behindSecondBit = currentNo.Substring(9, 1);
				var behindThirdBit = currentNo.Substring(8, 1);
				if (behindSecondBit == "9")
				{
					switch (behindThirdBit)
					{
						/*倒数第三位0,1,2,4,5,7,8 跳转 4 */
						case "0":
						case "1":
						case "2":
						case "4":
						case "5":
						case "7":
						case "8":
							newBehindFirstBit = MakeLastBit(behindFirstBit, 4);
							break;
						/*倒数第三位 3,6 跳转 5 */
						case "3":
						case "6":
							newBehindFirstBit = MakeLastBit(behindFirstBit, 5);
							break;
						/*倒数第三位 9 跳转 7 */
						case "9":
							newBehindFirstBit = MakeLastBit(behindFirstBit, 7);
							break;
					}
				}
				else
				{
					newBehindFirstBit = MakeLastBit(behindFirstBit, 1);
				}
				var tempLength = frontElevenBits.Length;
				var temp = Convert.ToInt64(frontElevenBits) + 1;
				return ((temp.ToString().Length < tempLength) ? "0" + temp.ToString() : temp.ToString()) + newBehindFirstBit;
			}
			else
			{
				return String.Empty;
			}
		}

		private static String MakeLastBit(String lastBit, Int32 step)
		{
			var temp = Convert.ToInt32(lastBit);
			if ((temp - step) >= 0)
			{
				return (temp - step).ToString();
			}
			else
			{
				return (10 + (temp - step)).ToString();
			}
		}

		#endregion
	}
}